package main

import (
	"flag"
	"fmt"
	"image"
	"image/jpeg"
	"image/png"
	"io/ioutil"
	"os"
	"runtime"
	//	"runtime/pprof"
	"sync"

	"github.com/nfnt/resize"
)

var (
	iosSizes        []uint = []uint{167, 152, 144, 180, 120, 114, 100, 87, 80, 76, 72, 60, 58, 57, 50, 40, 29, 20}
	iosContentsJson string = `
{
  "images" : [
    {
      "size" : "20x20",
      "idiom" : "iphone",
      "filename" : "icon40x40.png",
      "scale" : "2x"
    },
    {
      "size" : "20x20",
      "idiom" : "iphone",
      "filename" : "icon60x60.png",
      "scale" : "3x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "icon29x29.png",
      "scale" : "1x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "icon58x58.png",
      "scale" : "2x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "icon87x87.png",
      "scale" : "3x"
    },
    {
      "size" : "40x40",
      "idiom" : "iphone",
      "filename" : "icon80x80.png",
      "scale" : "2x"
    },
    {
      "size" : "40x40",
      "idiom" : "iphone",
      "filename" : "icon120x120.png",
      "scale" : "3x"
    },
    {
      "size" : "57x57",
      "idiom" : "iphone",
      "filename" : "icon57x57.png",
      "scale" : "1x"
    },
    {
      "size" : "57x57",
      "idiom" : "iphone",
      "filename" : "icon114x114.png",
      "scale" : "2x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "icon120x120.png",
      "scale" : "2x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "icon180x180.png",
      "scale" : "3x"
    },
    {
      "size" : "20x20",
      "idiom" : "ipad",
      "filename" : "icon20x20.png",
      "scale" : "1x"
    },
    {
      "size" : "20x20",
      "idiom" : "ipad",
      "filename" : "icon40x40.png",
      "scale" : "2x"
    },
    {
      "size" : "29x29",
      "idiom" : "ipad",
      "filename" : "icon29x29.png",
      "scale" : "1x"
    },
    {
      "size" : "29x29",
      "idiom" : "ipad",
      "filename" : "icon58x58.png",
      "scale" : "2x"
    },
    {
      "size" : "40x40",
      "idiom" : "ipad",
      "filename" : "icon40x40.png",
      "scale" : "1x"
    },
    {
      "size" : "40x40",
      "idiom" : "ipad",
      "filename" : "icon80x80.png",
      "scale" : "2x"
    },
    {
      "size" : "50x50",
      "idiom" : "ipad",
      "filename" : "icon50x50.png",
      "scale" : "1x"
    },
    {
      "size" : "50x50",
      "idiom" : "ipad",
      "filename" : "icon100x100.png",
      "scale" : "2x"
    },
    {
      "size" : "72x72",
      "idiom" : "ipad",
      "filename" : "icon72x72.png",
      "scale" : "1x"
    },
    {
      "size" : "72x72",
      "idiom" : "ipad",
      "filename" : "icon144x144.png",
      "scale" : "2x"
    },
    {
      "size" : "76x76",
      "idiom" : "ipad",
      "filename" : "icon76x76.png",
      "scale" : "1x"
    },
    {
      "size" : "76x76",
      "idiom" : "ipad",
      "filename" : "icon152x152.png",
      "scale" : "2x"
    },
    {
      "size" : "83.5x83.5",
      "idiom" : "ipad",
      "filename" : "icon167x167.png",
      "scale" : "2x"
    },
    {
      "size" : "1024x1024",
      "idiom" : "ios-marketing",
      "filename" : "icon1024x1024.jpg",
      "scale" : "1x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}
`

	androidSizes      []uint   = []uint{192, 144, 96, 72, 48}
	androidMipmapDirs []string = []string{"mipmap-xxxhdpi", "mipmap-xxhdpi", "mipmap-xhdpi", "mipmap-hdpi", "mipmap-mdpi"}
)

func resizePng(img image.Image, s uint, filepath string) error {
	m := resize.Resize(s, s, img, resize.Lanczos3)

	out, e := os.Create(filepath)
	if e != nil {
		return e
	}
	defer out.Close()

	e = png.Encode(out, m)

	return e
}

func makeIosIconset(src image.Image) error {
	outputDir := "ios/AppIcon.appiconset"
	if e := os.MkdirAll(outputDir, os.ModeDir|os.ModePerm); e != nil {
		return e
	}
	if e := ioutil.WriteFile(outputDir+"/Contents.json", []byte(iosContentsJson), os.ModePerm); e != nil {
		return e
	}
	wg := &sync.WaitGroup{}

	// 1024x1024 marketing jpg
	wg.Add(1)
	go func(src image.Image, outputDir string) {
		out, e := os.Create(fmt.Sprintf("%s/icon1024x1024.jpg", outputDir))
		if e != nil {
			panic(e)
		}
		defer out.Close()
		e = jpeg.Encode(out, src, &jpeg.Options{Quality: 100})
		if e != nil {
			panic(e)
		}
		wg.Done()
	}(src, outputDir)

	for _, s := range iosSizes {
		wg.Add(1)
		go func(src image.Image, s uint, outputDir string) {
			if e := resizePng(src, s, fmt.Sprintf("%s/icon%dx%d.png", outputDir, s, s)); e != nil {
				panic(e)
			}
			wg.Done()
		}(src, s, outputDir)
	}
	wg.Wait()
	return nil
}

func makeAndroidMipmaps(src image.Image) error {
	outputDir := "android/"
	for _, d := range androidMipmapDirs {
		if e := os.MkdirAll(outputDir+d, os.ModeDir|os.ModePerm); e != nil {
			return e
		}
	}
	wg := &sync.WaitGroup{}
	for i, s := range androidSizes {
		wg.Add(1)
		go func(src image.Image, s uint, outputDir string, mipmapDir string) {
			if e := resizePng(src, s, fmt.Sprintf("%s/%s/app_icon.png", outputDir, mipmapDir)); e != nil {
				panic(e)
			}
			wg.Done()
		}(src, s, outputDir, androidMipmapDirs[i])
	}
	wg.Wait()
	return nil
}

func checkImageSize(img image.Image, s int) error {
	size := img.Bounds().Size()
	if size.X < s || size.Y < s {
		return fmt.Errorf("image size is smaller than %d", s)
	}
	return nil
}

func getImage(filepath string) (image.Image, error) {
	f, e := os.Open(filepath)
	if e != nil {
		return nil, e
	}
	img, e := png.Decode(f)
	f.Close()
	return img, e
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	//	f, e := os.Create("prof.cpu")
	//	if e != nil {
	//		panic(e)
	//	}
	//	pprof.StartCPUProfile(f)
	//	defer pprof.StopCPUProfile()

	srcIOSPath := flag.String("ios", "ios.png", "iOS's icon source, base 1024x1024")
	srcAndroidPath := flag.String("android", "android.png", "Android's icon source. base 192x192")
	flag.Parse()

	if srcIOSPath != nil {
		srcIOSImg, e := getImage(*srcIOSPath)
		if e != nil {
			panic(e)
		}
		e = checkImageSize(srcIOSImg, 1024)
		if e != nil {
			panic(e)
		}
		if e := makeIosIconset(srcIOSImg); e != nil {
			panic(e)
		}
	}

	if srcAndroidPath != nil {
		srcAndroidImg, e := getImage(*srcAndroidPath)
		if e != nil {
			panic(e)
		}
		e = checkImageSize(srcAndroidImg, 192)
		if e != nil {
			panic(e)
		}
		if e := makeAndroidMipmaps(srcAndroidImg); e != nil {
			panic(e)
		}
	}
}
